package com.csdj.t309springboot.controller;
import com.csdj.t309springboot.common.CacheConstant;
import com.csdj.t309springboot.common.StatusContant;
import com.csdj.t309springboot.common.WebResult;
import com.csdj.t309springboot.common.WebResultMsgCode;
import com.csdj.t309springboot.entity.User;
import com.csdj.t309springboot.service.RedisService;
import com.csdj.t309springboot.service.UserService;
import com.csdj.t309springboot.utils.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.TreeMap;
/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author 谭湛宇
 * @since 2022-01-04
 */
@RestController
@RequestMapping("/user")
public class UserController extends BaseController {

    private Logger log = LoggerFactory.getLogger("userController");
    @Resource
    private UserService userService;
    @Resource
    private RedisService redisService;
    @Value("${file.upload.url}")
    private String uploadUrl;//文件上传路径
    @Value("${file.upload.prefix-url}")
    private String prefixUrl;//服务器路径前缀
    @Value("${file.upload.default-profile-photo}")
    private String defaultProfilePhoto;//默认头像路径
    //    @Resource
//    private RedisService redisService;
    @Autowired
    private WeiXinUtils weiXinService;

    /**
     * 微信测试号接入
     * @param request
     * @param response
     */
    @GetMapping("/wei/xin")
    public void wx(HttpServletRequest request, HttpServletResponse response) {
        //获取微信服务器发来的参数，并将token、timestamp、nonce三个参数进行字典序排序
        //将三个参数字符串拼接成一个字符串进行sha1加密
        //开发者获得加密后的字符串可与signature对比，标识该请求来源于微信
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        //check方法用来排序以及比较
        if (weiXinService.check(timestamp, nonce, signature)) {
            PrintWriter out = null;
            try {
                out = response.getWriter();
                out.print(echostr);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                out.flush();//刷新文件流
                out.close();//关闭文件流
            }
            System.out.println("接入成功");
        }
    }

    /**
     * 3.hash计算方法
     * 数据+身份识别id+身份密码 => hash算法加密 => hash
     * 把数据+身份识别id+hash发送给接收方
     * 把hash值发送给接收方验证接口验证值
     * 接收方需要对数据的可信度进行验证
     * 用以下条件对上面的接收的参数进行验证
     * 对参数进行排序,保证顺序一致
     * 如何排序 ?
     * 方法一:treeMap集合
     * 方法二:list对象.sort()
     * @param username
     * @param email
     * @param nickname
     * @param description             描述,说明
     * @param accessKey:abcdefg//访问密钥
     * @return
     */
    @PostMapping("/callback")
    public WebResult callback(
            @RequestParam("username") String username, @RequestParam("email") String email,
            @RequestParam("nickname") String nickname, @RequestParam("description") String description,
            @RequestParam("accessKey") String accessKey, @RequestParam("sign") String sign) {
        //accessKey : abcdefg
        //accessSecret:wienq31fj2ijsf21f2g3
        TreeMap<String, String> map = new TreeMap<>();
        map.put("username", username);
        map.put("email", email);
        map.put("nickname", nickname);
        map.put("description", description);
        map.put("accessKey", accessKey);
        if (!SignurateUtil.checkSign(map, sign)) {
            return new WebResult(WebResultMsgCode.FAIL);
        }
        return new WebResult(WebResultMsgCode.SUCCESS);
    }

    @GetMapping("/test")
    public String test() {
        return "";
    }

    @PostMapping("/login")
    public WebResult login(@RequestParam String username,
                           @RequestParam String password) {
        User user = userService.login(username, password);
        //用户被锁定
        if (user != null && StatusContant.USER_STATUS_LOCKED == user.getStatus()) {
            return new WebResult(WebResultMsgCode.USER_LOCKED);
        }
        if (user == null) {//密码输入错误; 6次密码错误之后，此账号当天不能再登录，提示“密码错误次数太多， 请明天再试”
            //自增错误次数并设置键的过期时间
            String stringIncorrectLoginPasswords = redisService.getString(CacheConstant.NUMBER_OF_INCORRECT_LOGIN_PASSWORDS + username);
            log.info("stringIncorrectLoginPasswords=" + stringIncorrectLoginPasswords);
            if (null != stringIncorrectLoginPasswords) {//不为空
                redisService.setString(CacheConstant.NUMBER_OF_INCORRECT_LOGIN_PASSWORDS + username,
                        String.valueOf(Integer.parseInt(stringIncorrectLoginPasswords) + 1), CalendarUtil.computationTime());
            } else {//为空
                redisService.setString(CacheConstant.NUMBER_OF_INCORRECT_LOGIN_PASSWORDS + username,
                        String.valueOf(1), CalendarUtil.computationTime());
            }
            //根据键获取自增后的值
            int incorrectLoginPasswords = Integer.parseInt(
                    redisService.getString(CacheConstant.NUMBER_OF_INCORRECT_LOGIN_PASSWORDS + username));
            log.info("incorrectLoginPasswords=" + incorrectLoginPasswords);
            if (incorrectLoginPasswords > 6) {//错误次数大于6
                return new WebResult(WebResultMsgCode.TOO_MANY_PASSWORD_ERRORS);
            }//小于6
            return new WebResult(WebResultMsgCode.USER_PWD_ERROR);
        }
        return new WebResult(WebResultMsgCode.SUCCESS).putData("user", user);
    }

    @GetMapping("/getInfo")
    public WebResult getInfo(HttpServletRequest request) {
        int uid = getUid(request);
        log.info("getInfo() uid=" + uid);
        User user = userService.getUserInfoById(uid);
        if (user != null) {
            //用户头像为空则设置默认头像
            if (user.getProfilePhoto() == null)
                user.setProfilePhoto(defaultProfilePhoto);
            return new WebResult(WebResultMsgCode.SUCCESS).putData("user", user);
        }
        return new WebResult(WebResultMsgCode.FAIL);
    }

    /**
     * @param id
     * @param password
     * @param nickname
     * @param signInNumberOfDays
     * @param score
     * @param selfIntroduction
     * @return
     */
    @PostMapping("/updateById")
    public WebResult update(@RequestParam Integer id, @RequestParam String password, String nickname,
                            Integer signInNumberOfDays, Integer score, String selfIntroduction) {

        User user = new User();
        user.setId(id);
        user.setPassword(password);
        user.setNickname(nickname);

        log.info("user=" + user);
        boolean update = userService.updateById(user);
        if (update) {
            return new WebResult(WebResultMsgCode.SUCCESS);
        }
        return new WebResult(WebResultMsgCode.FAIL);
    }

    @PostMapping("/updateNickname")
    public WebResult updateNickname(@RequestParam(value = "nickname", required = false) String nickname,
                                    Integer id, String selfIntroduction) {
        log.info("nickname=" + nickname);
        log.info("id=" + id);
        User user = new User();
        user.setId(id);
        user.setNickname(nickname);
        user.setSelfIntroduction(selfIntroduction);
        boolean update = userService.updateById(user);
        if (update) {
            return new WebResult(WebResultMsgCode.SUCCESS);
        }
        return new WebResult(WebResultMsgCode.FAIL);
    }

    /**
     * 用户注册功能, 需要开启事务
     *
     * @param email
     * @param password
     * @param invitationCode 邀请码
     * @return
     */
    @GetMapping("/register")
    public WebResult insert(@RequestParam(value = "email", required = true) String email,
                            @RequestParam(value = "password", required = true) String password,
                            @RequestParam String inputCheckCode,
                            @RequestParam(value = "invitationCode", required = false) String invitationCode) {
        log.info("email=" + email + ",password=" + password);
        log.info("邀请码invitationCode=" + invitationCode);
        //注册前看错误次数有没有大于6次,禁止注册
        //注册前判断邮箱验证码错误的次数,大于6次,则当天禁止注册, 把当前注册用户的邮箱拉入黑名单,
        int numberOfErrors = 0;
        String cacheCheckCode = redisService.getString(CacheConstant.CACHE_CHECK_CODE + email);
        log.info("cacheCheckCode=" + cacheCheckCode);
        log.info("inputCheckCode=" + inputCheckCode);
        if (inputCheckCode == null || inputCheckCode == "") {//用户输入的邮箱验证码为空时
            return new WebResult(WebResultMsgCode.SUCCESS).putData("message", "请输入验证码");
        } else if (cacheCheckCode == null || cacheCheckCode == "") {//生成的邮箱验证码为空时
            return new WebResult(WebResultMsgCode.SUCCESS).putData("message", "验证码已过期, 请重新获取验证码");
        } else if (!cacheCheckCode.equals(inputCheckCode)) {//验证码错误时,错误次数加 1
            //获取错误次数
            String cache = redisService.getString(CacheConstant.CACHE_NUMBER_OF_ERRORS + email);
            //如果错误多次
            if (null != cache) {
                //redis错误次数
                int redisNumberOfErrors = Integer.parseInt(redisService.getString(CacheConstant.CACHE_NUMBER_OF_ERRORS + email));

                ++redisNumberOfErrors;
                log.info("++numberOfErrors=" + redisNumberOfErrors);
                if (redisNumberOfErrors <= 6) {
                    //错误六次以下//错误两次及以上
                    redisService.setString(CacheConstant.CACHE_NUMBER_OF_ERRORS + email, String.valueOf(redisNumberOfErrors), CalendarUtil.computationTime());
                    log.info("redis numberOfErrors=" + redisService.getString(CacheConstant.CACHE_NUMBER_OF_ERRORS + email));
                    return new WebResult(WebResultMsgCode.SUCCESS).putData("message", "验证码错误");
                } else if (redisNumberOfErrors > 6) {
                    return new WebResult(WebResultMsgCode.SUCCESS).putData("message", "验证码错误次数太多，请明天再试");
                }
            }
            //如果是第一次错误
            log.info("验证码第一次错误");
            redisService.setString(CacheConstant.CACHE_NUMBER_OF_ERRORS + email, String.valueOf(1), CalendarUtil.computationTime());
            return new WebResult(WebResultMsgCode.SUCCESS).putData("message", "验证码错误");
        }//验证码正确时
        //生成个人邀请码和个人邀请链接
        String userInvitationCode = RandomUtil.getInvitationCode();
        String userInviteLink = RandomUtil.getInviteLink();
        User user = new User();
        user.setEmail(email);
        user.setPassword(password.trim());
        //给用户设置默认头像
        user.setProfilePhoto(defaultProfilePhoto);
        //检查邀请码是否存在
        User checkInvitationCode = userService.checkInvitationCode(invitationCode);
        if (null != checkInvitationCode) {//如果输入的邀请码存在,此对象是上级用户
            //给上级用户增加积分
            checkInvitationCode.setIntegralNumber(checkInvitationCode.getIntegralNumber() + 100);

            userService.updateById(checkInvitationCode);

            //修改当前用户的上级 id为邀请人的 id
            user.setTopId(checkInvitationCode.getId());
        }
        //输入的邀请码不存在,上级编号为0
        user.setTopId(0);
        //如果随机生成的个人邀请码和个人邀请链接重复,则重新生成
        if (null == userService.checkInvitationCode(userInvitationCode)) {//验证输入的邀请码是否存在
            user.setInvitationCode(RandomUtil.getInvitationCode());//设置每个人唯一的邀请码
        }
        if (null == userService.checkInviteLink(userInviteLink)) {
            user.setInvitationCode(RandomUtil.getInviteLink());//设置每个人唯一的邀请码
        }
        user.setInvitationCode(userInvitationCode);//设置邀请码
        user.setInviteLink(userInviteLink);//设置邀请链接
        int insert = userService.insert(user);
        log.info("insert=" + insert);
        if (insert > 0) {
            return new WebResult(WebResultMsgCode.SUCCESS).putData("message", "注册成功");
        }
        return new WebResult(WebResultMsgCode.SUCCESS).putData("message", "注册失败");
    }

    /**
     * 动态验证输入的邮箱是否已经注册
     */
    @PostMapping("/checkEmail")
    public WebResult checkEmail(String email) {
        User user = userService.checkMail(email);
        if (null == user) {
            return new WebResult(WebResultMsgCode.SUCCESS).putData("message", "该邮箱可以注册");
        }
        return new WebResult(WebResultMsgCode.SUCCESS).putData("message", "该邮箱已经注册");
    }

    /**
     * 动态验证输入的邮箱是否已经注册
     */
    @GetMapping("/checkCode")
    public WebResult checkCode(@RequestParam String checkCode) {
        String cacheCheckCode = redisService.getString(CacheConstant.CACHE_CHECK_CODE);
        log.info("cacheCheckCode=" + cacheCheckCode);
        log.info("checkCode=" + checkCode);
        if (checkCode != null || checkCode != "") {
            if (cacheCheckCode.equals(checkCode)) {
                return new WebResult(WebResultMsgCode.SUCCESS).putData("message", true);
            }
        }
        return new WebResult(WebResultMsgCode.SUCCESS).putData("message", false);
    }

    @GetMapping("/delete")
    public WebResult delete(@RequestParam(value = "id", required = true) int id) {
        log.info("id=" + id);

        int delete = userService.delete(id);
        if (delete > 0) {
            return new WebResult(WebResultMsgCode.SUCCESS).putData("id", delete);
        }

        return null;
    }

    @ResponseBody
    @GetMapping("/list")
    public WebResult list() {
        List<User> list = userService.getAllUsers();
        if (null != list) {
            return new WebResult(WebResultMsgCode.SUCCESS).putData("user", list);
        }
        return null;
    }


    /**
     * 模糊查询
     *
     * @param column 列名
     * @return
     */
    @ResponseBody
    @GetMapping("/fuzzySearch")
    public WebResult fuzzySearch(@RequestParam(value = "column", required = false) String column) {
        List<User> list = userService.getAllUsersByMoHuChaXun(column);
        if (null != list) {
            return new WebResult(WebResultMsgCode.SUCCESS).putData("user", list);
        }
        return null;
    }

    /**
     * 上传头像,修改头像
     */
    @PostMapping("/upload")
    public WebResult singleFileUpload(@RequestParam("file") MultipartFile file,
                                      HttpServletRequest request) {

        int uid = getUid(request);
        log.info("uid=" + uid);
        //@RequestParam("file") MultipartFile file为接收图片参数
        //Integer userId,String status 用户Id和状态
        try {
            byte[] bytes = file.getBytes();
            String imageFileName = file.getOriginalFilename();
            log.info("imageFileName=" + imageFileName);

            String fileName = UpPhotoNameUtils.getPhotoName("img", imageFileName);
            log.info("fileName=" + fileName);
            //“D:\idea-project2\PinTu\src\main\resources\static\assets\”为本地目录
            //路径不要写死了, 要引用配置文件的
            Path path = Paths.get(uploadUrl + fileName);
            Files.write(path, bytes);//写入文件
            //把图片名称写入数据库
            //路径不要写死了, 要引用配置文件的
            log.info("prefixUrl=" + prefixUrl);
            String avatarUrl = prefixUrl + fileName;
            log.info("avatarUrl" + avatarUrl);
            User user = new User();
            user.setId(uid);
            user.setProfilePhoto(avatarUrl);//头像
            //修改用户头像
            userService.updateById(user);
            //返回文件名字
            return new WebResult(WebResultMsgCode.SUCCESS).putData("fileName", fileName);
        } catch (IOException e) {
            log.error("error: " + e.getMessage());
        }
        return new WebResult(WebResultMsgCode.FAIL);
    }


}
